use crate::error::Result;
use crate::storage::data_types::traits::{DataType, SortedSetOperations};
use crate::core::collections::skip_list::SkipList;
use std::any::Any;
use fxhash::FxHashMap;

/// Sorted Set data type implementation
/// 
/// Represents a Redis sorted set value, which is a collection of unique strings
/// where each string is associated with a floating-point score. Elements are
/// ordered by their scores in ascending order. Uses high-performance FxHashMap.
#[derive(Debug, Clone)]
pub struct SortedSetType {
    /// Skip list for ordered operations by score
    skip_list: SkipList<String>,
    /// Hash map for O(1) member-to-score lookup with FxHash
    member_scores: FxHashMap<String, f64>,
}

impl SortedSetType {
    /// Create a new empty sorted set
    pub fn new() -> Self {
        Self {
            skip_list: SkipList::new(),
            member_scores: FxHashMap::default(),
        }
    }
    
    /// Create a sorted set from a vector of (score, member) pairs
    pub fn from_vec(data: Vec<(f64, String)>) -> Self {
        let mut sorted_set = Self::new();
        for (score, member) in data {
            sorted_set.add_member(score, member);
        }
        sorted_set
    }
    
    /// Internal method to add a member with a score
    fn add_member(&mut self, score: f64, member: String) -> bool {
        // If member already exists, remove it first
        if let Some(old_score) = self.member_scores.remove(&member) {
            self.skip_list.remove(old_score, &member);
        }
        
        // Add the member with new score
        self.member_scores.insert(member.clone(), score);
        self.skip_list.insert(score, member)
    }
    
    /// Internal method to remove a member
    fn remove_member(&mut self, member: &str) -> bool {
        if let Some(score) = self.member_scores.remove(member) {
            self.skip_list.remove(score, &member.to_string())
        } else {
            false
        }
    }
    
    /// Helper to normalize range indices for ZRANGE operations
    fn normalize_range(&self, start: i64, stop: i64) -> (usize, usize) {
        let len = self.skip_list.len() as i64;
        
        if len == 0 {
            return (0, 0);
        }
        
        // Normalize start
        let start = if start < 0 {
            std::cmp::max(0, len + start)
        } else {
            std::cmp::min(start, len - 1)
        } as usize;
        
        // Normalize stop
        let stop = if stop < 0 {
            std::cmp::max(-1, len + stop)
        } else {
            std::cmp::min(stop, len - 1)
        } as usize;
        
        (start, stop)
    }
    
    /// Calculate memory usage
    fn calculate_memory_usage(&self) -> usize {
        let base_size = std::mem::size_of::<Self>();
        let map_overhead = self.member_scores.capacity() * std::mem::size_of::<(String, f64)>();
        let content_size: usize = self.member_scores
            .keys()
            .map(|s| s.len())
            .sum();
        
        base_size + map_overhead + content_size
    }
}

impl Default for SortedSetType {
    fn default() -> Self {
        Self::new()
    }
}

impl DataType for SortedSetType {
    fn type_name(&self) -> &'static str {
        "zset"
    }
    
    fn debug_string(&self) -> String {
        format!("SortedSetType({} members)", self.member_scores.len())
    }
    
    fn clone_data(&self) -> Box<dyn DataType> {
        Box::new(self.clone())
    }
    
    fn is_empty(&self) -> bool {
        self.member_scores.is_empty()
    }
    
    fn memory_usage(&self) -> usize {
        self.calculate_memory_usage()
    }
    
    fn as_any(&self) -> &dyn Any {
        self
    }
    
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }
}

impl SortedSetOperations for SortedSetType {
    fn zadd(&mut self, members: Vec<(f64, String)>) -> Result<usize> {
        let mut added_count = 0;
        
        for (score, member) in members {
            if !self.member_scores.contains_key(&member) {
                added_count += 1;
            }
            self.add_member(score, member);
        }
        
        Ok(added_count)
    }
    
    fn zrem(&mut self, members: &[String]) -> Result<usize> {
        let mut removed_count = 0;
        
        for member in members {
            if self.remove_member(member) {
                removed_count += 1;
            }
        }
        
        Ok(removed_count)
    }
    
    fn zscore(&self, member: &str) -> Result<Option<f64>> {
        Ok(self.member_scores.get(member).copied())
    }
    
    fn zrank(&self, member: &str) -> Result<Option<usize>> {
        if let Some(&score) = self.member_scores.get(member) {
            Ok(self.skip_list.get_rank(score, &member.to_string()))
        } else {
            Ok(None)
        }
    }
    
    fn zrevrank(&self, member: &str) -> Result<Option<usize>> {
        if let Some(rank) = self.zrank(member)? {
            Ok(Some(self.skip_list.len() - 1 - rank))
        } else {
            Ok(None)
        }
    }
    
    fn zcard(&self) -> Result<usize> {
        Ok(self.member_scores.len())
    }
    
    fn zcount(&self, min: f64, max: f64) -> Result<usize> {
        Ok(self.skip_list.get_range_by_score(min, max).len())
    }
    
    fn zrange(&self, start: i64, stop: i64, with_scores: bool) -> Result<Vec<(String, Option<f64>)>> {
        let (start_idx, stop_idx) = self.normalize_range(start, stop);
        
        if start_idx > stop_idx {
            return Ok(Vec::new());
        }
        
        let nodes = self.skip_list.get_range_by_rank(start_idx, stop_idx);
        let mut result = Vec::new();
        
        for node in nodes {
            if with_scores {
                result.push((node.value, Some(node.score)));
            } else {
                result.push((node.value, None));
            }
        }
        
        Ok(result)
    }
    
    fn zrevrange(&self, start: i64, stop: i64, with_scores: bool) -> Result<Vec<(String, Option<f64>)>> {
        let len = self.skip_list.len() as i64;
        
        if len == 0 {
            return Ok(Vec::new());
        }
        
        // Convert reverse indices to forward indices
        let rev_start = len - 1 - stop;
        let rev_stop = len - 1 - start;
        
        let mut result = self.zrange(rev_start, rev_stop, with_scores)?;
        result.reverse();
        Ok(result)
    }
    
    fn zrangebyscore(
        &self, 
        min: f64, 
        max: f64, 
        with_scores: bool, 
        limit: Option<(usize, usize)>
    ) -> Result<Vec<(String, Option<f64>)>> {
        let mut nodes = self.skip_list.get_range_by_score(min, max);
        
        // Apply limit if specified (offset, count)
        if let Some((offset, count)) = limit {
            if offset >= nodes.len() {
                nodes.clear();
            } else {
                let end = std::cmp::min(offset + count, nodes.len());
                nodes = nodes[offset..end].to_vec();
            }
        }
        
        let mut result = Vec::new();
        for node in nodes {
            if with_scores {
                result.push((node.value, Some(node.score)));
            } else {
                result.push((node.value, None));
            }
        }
        
        Ok(result)
    }
    
    fn zrevrangebyscore(
        &self, 
        max: f64, 
        min: f64, 
        with_scores: bool, 
        limit: Option<(usize, usize)>
    ) -> Result<Vec<(String, Option<f64>)>> {
        let mut result = self.zrangebyscore(min, max, with_scores, None)?;
        result.reverse();
        
        // Apply limit if specified
        if let Some((offset, count)) = limit {
            if offset >= result.len() {
                result.clear();
            } else {
                let end = std::cmp::min(offset + count, result.len());
                result = result[offset..end].to_vec();
            }
        }
        
        Ok(result)
    }
    
    fn zremrangebyrank(&mut self, start: i64, stop: i64) -> Result<usize> {
        let (start_idx, stop_idx) = self.normalize_range(start, stop);
        
        if start_idx > stop_idx {
            return Ok(0);
        }
        
        let nodes = self.skip_list.get_range_by_rank(start_idx, stop_idx);
        let mut removed_count = 0;
        
        for node in nodes {
            if self.remove_member(&node.value) {
                removed_count += 1;
            }
        }
        
        Ok(removed_count)
    }
    
    fn zremrangebyscore(&mut self, min: f64, max: f64) -> Result<usize> {
        let nodes = self.skip_list.get_range_by_score(min, max);
        let mut removed_count = 0;
        
        for node in nodes {
            if self.remove_member(&node.value) {
                removed_count += 1;
            }
        }
        
        Ok(removed_count)
    }
    
    fn zincrby(&mut self, increment: f64, member: &str) -> Result<f64> {
        let current_score = self.member_scores.get(member).copied().unwrap_or(0.0);
        let new_score = current_score + increment;
        
        self.add_member(new_score, member.to_string());
        Ok(new_score)
    }
}

impl From<Vec<(f64, String)>> for SortedSetType {
    fn from(data: Vec<(f64, String)>) -> Self {
        Self::from_vec(data)
    }
}

impl From<&[(f64, String)]> for SortedSetType {
    fn from(data: &[(f64, String)]) -> Self {
        Self::from_vec(data.to_vec())
    }
}

impl FromIterator<(f64, String)> for SortedSetType {
    fn from_iter<T: IntoIterator<Item = (f64, String)>>(iter: T) -> Self {
        let data: Vec<(f64, String)> = iter.into_iter().collect();
        Self::from_vec(data)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_sorted_set_basic_operations() {
        let mut zset = SortedSetType::new();
        
        assert!(zset.is_empty());
        assert_eq!(zset.zcard().unwrap(), 0);
        
        // Test zadd
        let added = zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (3.0, "three".to_string()),
        ]).unwrap();
        assert_eq!(added, 3);
        assert_eq!(zset.zcard().unwrap(), 3);
        
        // Test adding duplicate
        let added = zset.zadd(vec![
            (1.5, "one".to_string()), // Update existing
            (4.0, "four".to_string()),  // Add new
        ]).unwrap();
        assert_eq!(added, 1); // Only "four" was new
        assert_eq!(zset.zcard().unwrap(), 4);
    }
    
    #[test]
    fn test_sorted_set_score_operations() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (3.0, "three".to_string()),
        ]).unwrap();
        
        // Test zscore
        assert_eq!(zset.zscore("one").unwrap(), Some(1.0));
        assert_eq!(zset.zscore("two").unwrap(), Some(2.0));
        assert_eq!(zset.zscore("three").unwrap(), Some(3.0));
        assert_eq!(zset.zscore("nonexistent").unwrap(), None);
        
        // Test zincrby
        let new_score = zset.zincrby(2.5, "one").unwrap();
        assert_eq!(new_score, 3.5);
        assert_eq!(zset.zscore("one").unwrap(), Some(3.5));
        
        // Test zincrby on nonexistent member
        let new_score = zset.zincrby(5.0, "five").unwrap();
        assert_eq!(new_score, 5.0);
        assert_eq!(zset.zcard().unwrap(), 4);
    }
    
    #[test]
    fn test_sorted_set_rank_operations() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (3.0, "three".to_string()),
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (4.0, "four".to_string()),
        ]).unwrap();
        
        // Test zrank (0-based, lowest score first)
        assert_eq!(zset.zrank("one").unwrap(), Some(0));
        assert_eq!(zset.zrank("two").unwrap(), Some(1));
        assert_eq!(zset.zrank("three").unwrap(), Some(2));
        assert_eq!(zset.zrank("four").unwrap(), Some(3));
        assert_eq!(zset.zrank("nonexistent").unwrap(), None);
        
        // Test zrevrank (0-based, highest score first)
        assert_eq!(zset.zrevrank("four").unwrap(), Some(0));
        assert_eq!(zset.zrevrank("three").unwrap(), Some(1));
        assert_eq!(zset.zrevrank("two").unwrap(), Some(2));
        assert_eq!(zset.zrevrank("one").unwrap(), Some(3));
    }
    
    #[test]
    fn test_sorted_set_range_operations() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (3.0, "three".to_string()),
            (4.0, "four".to_string()),
            (5.0, "five".to_string()),
        ]).unwrap();
        
        // Test zrange without scores
        let range = zset.zrange(0, 2, false).unwrap();
        assert_eq!(range.len(), 3);
        assert_eq!(range[0], ("one".to_string(), None));
        assert_eq!(range[1], ("two".to_string(), None));
        assert_eq!(range[2], ("three".to_string(), None));
        
        // Test zrange with scores
        let range = zset.zrange(1, 3, true).unwrap();
        assert_eq!(range.len(), 3);
        assert_eq!(range[0], ("two".to_string(), Some(2.0)));
        assert_eq!(range[1], ("three".to_string(), Some(3.0)));
        assert_eq!(range[2], ("four".to_string(), Some(4.0)));
        
        // Test zrevrange
        let range = zset.zrevrange(0, 2, false).unwrap();
        assert_eq!(range.len(), 3);
        assert_eq!(range[0], ("five".to_string(), None));
        assert_eq!(range[1], ("four".to_string(), None));
        assert_eq!(range[2], ("three".to_string(), None));
        
        // Test negative indices
        let range = zset.zrange(-2, -1, false).unwrap();
        assert_eq!(range.len(), 2);
        assert_eq!(range[0], ("four".to_string(), None));
        assert_eq!(range[1], ("five".to_string(), None));
    }
    
    #[test]
    fn test_sorted_set_score_range() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.5, "two_five".to_string()),
            (3.0, "three".to_string()),
            (4.5, "four_five".to_string()),
            (5.0, "five".to_string()),
        ]).unwrap();
        
        // Test zrangebyscore
        let range = zset.zrangebyscore(2.0, 4.0, false, None).unwrap();
        assert_eq!(range.len(), 2);
        assert_eq!(range[0], ("two_five".to_string(), None));
        assert_eq!(range[1], ("three".to_string(), None));
        
        // Test with scores
        let range = zset.zrangebyscore(2.0, 4.0, true, None).unwrap();
        assert_eq!(range[0], ("two_five".to_string(), Some(2.5)));
        assert_eq!(range[1], ("three".to_string(), Some(3.0)));
        
        // Test with limit
        let range = zset.zrangebyscore(1.0, 5.0, false, Some((1, 2))).unwrap();
        assert_eq!(range.len(), 2);
        assert_eq!(range[0], ("two_five".to_string(), None));
        assert_eq!(range[1], ("three".to_string(), None));
        
        // Test zrevrangebyscore
        let range = zset.zrevrangebyscore(4.0, 2.0, false, None).unwrap();
        assert_eq!(range.len(), 2);
        assert_eq!(range[0], ("three".to_string(), None));
        assert_eq!(range[1], ("two_five".to_string(), None));
    }
    
    #[test]
    fn test_sorted_set_count() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (3.0, "three".to_string()),
            (4.0, "four".to_string()),
            (5.0, "five".to_string()),
        ]).unwrap();
        
        assert_eq!(zset.zcount(2.0, 4.0).unwrap(), 3);
        assert_eq!(zset.zcount(1.5, 2.5).unwrap(), 1);
        assert_eq!(zset.zcount(10.0, 20.0).unwrap(), 0);
    }
    
    #[test]
    fn test_sorted_set_remove_operations() {
        let mut zset = SortedSetType::new();
        zset.zadd(vec![
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
            (3.0, "three".to_string()),
            (4.0, "four".to_string()),
            (5.0, "five".to_string()),
        ]).unwrap();
        
        // Test zrem
        let removed = zset.zrem(&["two".to_string(), "nonexistent".to_string()]).unwrap();
        assert_eq!(removed, 1);
        assert_eq!(zset.zcard().unwrap(), 4);
        assert_eq!(zset.zscore("two").unwrap(), None);
        
        // Test zremrangebyrank
        let removed = zset.zremrangebyrank(1, 2).unwrap();
        assert_eq!(removed, 2); // Remove "three" and "four"
        assert_eq!(zset.zcard().unwrap(), 2);
        
        // Test zremrangebyscore
        let removed = zset.zremrangebyscore(4.5, 6.0).unwrap();
        assert_eq!(removed, 1); // Remove "five"
        assert_eq!(zset.zcard().unwrap(), 1);
        assert_eq!(zset.zscore("one").unwrap(), Some(1.0));
    }
    
    #[test]
    fn test_sorted_set_conversions() {
        let data = vec![
            (3.0, "three".to_string()),
            (1.0, "one".to_string()),
            (2.0, "two".to_string()),
        ];
        
        let zset = SortedSetType::from(data);
        assert_eq!(zset.zcard().unwrap(), 3);
        
        // Should be ordered by score
        let range = zset.zrange(0, -1, false).unwrap();
        assert_eq!(range[0].0, "one");
        assert_eq!(range[1].0, "two");
        assert_eq!(range[2].0, "three");
    }
    
    #[test]
    fn test_data_type_trait() {
        let zset = SortedSetType::new();
        
        assert_eq!(zset.type_name(), "zset");
        assert!(zset.is_empty());
        assert!(zset.memory_usage() > 0);
        
        let cloned = zset.clone_data();
        assert_eq!(cloned.type_name(), "zset");
    }
}